#include "TcpServer.hpp"
#include <unordered_map>
#include "util.hpp"
const string gblank = " ";
const string gblankline = "\r\n";
const string gkeyvalue = ": ";
const string webroot = "./wwwroot";
const string homepage = "index.html";
const string page_404 = "/404.html";
class HttpRequest
{
public:
    HttpRequest()
        : _is_interact(false)
    {
    }
    ~HttpRequest() {}
    void ParseReqLine(string &reqline)
    {
        stringstream ss(reqline);
        ss >> _method >> _uri >> _version;
    }
    bool DeSerialize(string req_str)
    {
        string reqline;
        bool res = Util::GetOneLine(req_str, &reqline, gblankline);
        ParseReqLine(reqline);

        if (_uri == "/")
            _uri = webroot + _uri + homepage;
        else
            _uri = webroot + _uri;
        LOG(LogLevel::DEBUG) << "_method: " << _method;
        LOG(LogLevel::DEBUG) << "_uri: " << _uri;
        LOG(LogLevel::DEBUG) << "_version: " << _version;
        string tmp = "?";
        auto pos = _uri.find(tmp);
        if (pos == string::npos)
        {
            return true;
        }
        _args = _uri.substr(pos + tmp.size());
        _uri = _uri.substr(0, pos);
        _is_interact = true;

        return true;
    }

    string Uri() { return _uri; }
    bool IsInteract() { return _is_interact; }
    string Args() { return _args; }
    string Text() { return _text; }
    string Version() { return _version; }
private:
    string _method;
    string _uri;
    string _version;
    unordered_map<string, string> _headers;
    string _blank_line;
    string _text;
    string _args;
    bool _is_interact;
};

class HttpResponse
{
public:
    HttpResponse()
        : _blank_line(gblankline), _version("HTTP/1.1"), _code(200), _description("OK"), _keep_alive(true), _timeout(60)
    {
    }
    string Serialize()
    {
        string status_line = _version + gblank + to_string(_code) + gblank + _description + gblankline;
        if (_keep_alive)
        {
            SetHeader("Connection", "keep-alive");
            SetHeader("Keep-Alive", "timeout=" + to_string(_timeout));
        }
        else
        {
            SetHeader("Connection", "close");
        }
        string resp_header;
        for (auto &header : _headers)
        {
            string line = header.first + gkeyvalue + header.second + gblankline;
            resp_header += line;
        }

        return status_line + resp_header + _blank_line + _text;
    }
    void SetKeepAlive(bool keep_alive, int timeout = 60)
    {
        _keep_alive = keep_alive;
        _timeout = timeout;
    }
    void SetTargetFile(const string &target)
    {
        _targetfile = target;
    }
    void SetCode(int code)
    {
        _code = code;
        switch (_code)
        {
        case 200:
            _description = "OK";
            break;
        case 302:
            _description = "See Other";
        case 404:
            _description = "Not Found";
            break;
        case 307:
            _description = "Temporary Redirect";
        case 308:
            _description = " Permanent Redirect";
        default:
            break;
        }
    }
    void SetHeader(const string &key, const string &value)
    {
        auto iter = _headers.find(key);
        if (iter != _headers.end())
            return;
        _headers.insert({key, value});
    }
    string Uri2Suffix(const string &targetfile)
    {

        auto pos = targetfile.rfind(".");
        if (pos == string::npos)
        {
            return "text/html";
        }

        string suffix = targetfile.substr(pos);
        if (suffix == ".html" || suffix == ".htm")
            return "text/html";
        else if (suffix == ".jpg")
            return "image/jpeg";
        else if (suffix == "png")
            return "image/png";
        else
            return "";
    }

    bool MakeResponse()
    {
        if (_targetfile == "./wwwroot/favicon.ico")
        {
            LOG(LogLevel::DEBUG) << "用户请求: " << _targetfile << "忽略它";
            return false;
        }
        if (_targetfile == "./wwwroot/redirect_test")
        {
            SetCode(302);
            // SetCode(308);
            SetHeader("Location", "https://www.csdn.net/");
            return true;
        }
        int filesize = 0;
        bool res = Util::ReadFileContent(_targetfile, &_text);
        if (!res)
        {
            _text = "";
            LOG(LogLevel::WARNING) << "client want get " << _targetfile << " but not found";
            SetCode(404);
            _targetfile = webroot + page_404;
            filesize = Util::FileSize(_targetfile);
            Util::ReadFileContent(_targetfile, &_text);
            string suffix = Uri2Suffix(_targetfile);
            SetHeader("Content-Type", suffix);
            SetHeader("Content-Length", to_string(filesize));
            // SetCode(302);
            // SetHeader("Location","http://113.44.3.66:8080/404.html");
            // return true;
        }
        else
        {
            LOG(LogLevel::DEBUG) << "读取文件: " << _targetfile;
            SetCode(200);
            filesize = Util::FileSize(_targetfile);
            string suffix = Uri2Suffix(_targetfile);
            SetHeader("Content-Type", suffix);
            SetHeader("Content-Length", to_string(filesize));
        }
        return true;
    }
    void SetText(string &text) { _text = text; }

    ~HttpResponse() {}

public:
    string _version;

    int _code;
    string _description;
    unordered_map<string, string> _headers;
    string _blank_line;
    string _text;
    bool _keep_alive;
    int _timeout;
    string _targetfile;
};

using HttpFunc = function<void(HttpRequest &req, HttpResponse &resp)>;
class Http
{
public:
    Http(uint16_t port, int keep_alive_timeout = 60)
        : _tcpserver(make_unique<TcpServer>(port)), _keep_alive_timeout(keep_alive_timeout)
    {
    }
    void HandlerHttpRquest(shared_ptr<Socket> &sock, INETADDR &client)
    {
        bool keep_alive = true;

        while (keep_alive)
        {
            string req_str;
            int n = sock->Recv(&req_str);

            if (n <= 0)
            {
                if (n == 0)
                {
                    LOG(LogLevel::DEBUG) << "client closed connection";
                }
                else
                {
                    LOG(LogLevel::ERROR) << "recv error from client";
                }
                break;
            }
            cout << "#################################################" << endl;
            cout << req_str;
            cout << "#################################################" << endl;

            HttpRequest req;
            if (!req.DeSerialize(req_str))
            {
                LOG(LogLevel::ERROR) << "Failed to parse HTTP request";
                break;
            }

            HttpResponse resp;

            // 检查客户端是否请求保持连接
            string connection_header = Util::GetHeaderValue(req_str, "Connection");
            bool client_wants_keepalive = (connection_header == "keep-alive" ||
                                           (req.Version() == "HTTP/1.1" && connection_header != "close"));
            resp.SetKeepAlive(client_wants_keepalive, _keep_alive_timeout);

            if (req.IsInteract())
            {
                cout << "_uri: " << req.Uri() << endl;
                if (_route.find(req.Uri()) == _route.end())
                {
                    resp.SetCode(302);
                    resp.SetHeader("Location", "./wwwroot/404.html");
                }
                else
                {
                    _route[req.Uri()](req, resp);
                    string response_str = resp.Serialize();
                    sock->Send(response_str);
                }
            }
            else
            {
                resp.SetTargetFile(req.Uri());
                if (resp.MakeResponse())
                {
                    string response_str = resp.Serialize();
                    sock->Send(response_str);
                }
            }

            // 如果客户端或服务器不想保持连接，则退出循环
            keep_alive = client_wants_keepalive && resp._keep_alive;
        }
        sock->Close();
    }
    // string req_str;
    // int n = sock->Recv(&req_str);
    // if (n > 0)
    // {
    //     cout << "#################################################" << endl;
    //     cout << req_str;
    //     cout << "#################################################" << endl;
    //     HttpRequest req;
    //     req.DeSerialize(req_str);
    //     HttpResponse resp;

    //     if (req.IsInteract())
    //     {
    //         cout << "_uri: " << req.Uri() << endl;
    //         // _uri: ./wwwroot/login
    //         if (_route.find(req.Uri()) == _route.end())
    //         {
    //             resp.SetCode(302);
    //             resp.SetHeader("Location", "./wwwroot/404.html");
    //         }
    //         else
    //         {
    //             _route[req.Uri()](req, resp);
    //             string response_str = resp.Serialize();
    //             sock->Send(response_str);
    //         }
    //     }
    //     else
    //     {
    //         resp.SetTargetFile(req.Uri());
    //         if (resp.MakeResponse())
    //         {
    //             string response_str = resp.Serialize();
    //             sock->Send(response_str);
    //         }
    //     }
    // }
    // else if (n == 0)
    // {
    //     LOG(LogLevel::DEBUG) << "client exit";
    // }
    // else
    // {
    //     LOG(LogLevel::ERROR) << "client erro";
    // }

    void Start()
    {
        _tcpserver->Start([this](shared_ptr<Socket> &sock, INETADDR &client)
                          { this->HandlerHttpRquest(sock, client); });
    }
    void HttpService(string name, HttpFunc f)
    {
        string key = webroot + name;
        auto iter = _route.find(key);
        if (iter == _route.end())
        {
            _route.insert({key, f});
        }
    }
    ~Http()
    {
    }

private:
    unique_ptr<TcpServer> _tcpserver;
    unordered_map<string, HttpFunc> _route;
    int _keep_alive_timeout;
};
